# encoding:utf-8
from datetime import datetime
import json
import sys
import re
import click
from unipath import Path, FILES
from typing import Union, Dict, List
from loguru import logger

# 配置日志
logger.remove()  # 移除默认的处理器

# 添加控制台处理器
logger.add(
    sys.stdout,
    format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>",
    level="INFO"
)
# 添加文件处理器
logger.add(
    "logs/jav_process_ai_{time:YYYY-MM-DD}.log",
    rotation="00:00",  # 每天轮换
    retention="30 days",  # 保留30天
    format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {name}:{function}:{line} - {message}",
    level="DEBUG",
    encoding="utf-8"
)

"""
click.option()是Python中click包的一个装饰器，用于为命令行接口添加选项参数。它接受以下参数：
name（必需）：选项的名称，通常以短横线开头，如-f或--file。
flag（可选）：布尔标志，如果指定，则该选项不需要值。默认为False。
required（可选）：布尔值，表示该选项是否必须提供。默认为False。
help（可选）：选项的帮助信息，将在命令行中使用--help时显示。
type（可选）：选项的数据类型，例如int、float等。
default（可选）：选项的默认值。
show_default（可选）：布尔值，表示是否在帮助信息中显示默认值。默认为True。
callback（可选）：一个回调函数，当选项被设置时调用。
multiple（可选）：布尔值，表示该选项是否可以多次使用。默认为False。
expose_value（可选）：布尔值，表示是否将选项的值传递给回调函数。默认为True。
"""

# 视频文件
VIDEO_TYPE = ['.mp4', '.avi', '.rmvb', '.wmv', '.mov', '.mkv', '.flv', '.ts', '.webm', '.iso', '.m2ts', '.mpg', '.m4v']
# 脚本目录
SCRIPT_DIR = r'./script'
TEMP_DIR = r'./temp'
RECORD_FILE = r'./data/record_file.txt'


@click.group()
def main():
    pass


@main.command()
# Click 库中的一个装饰器，用于将一个函数标记为一个子命令
# @main.command()没有传入一个字符串参数，因此该命令的名称会默认为被装饰函数的名字，这里为'check_movie_info'
# @main.command('command2xxx')
# @main.command()传入一个字符串参数'command2xxx'，因此该命令的名称为'command2xxx'
@click.option("--dir-path", required=True, help="需要检查的目录路径", default="E:\临时文件\数据工厂\success", show_default=True)
def check_movie_info(dir_path: str) -> None:
    """
    检查媒体目录是否符合刮削规范

    参数:
        dir_path (str): 要检查的根目录路径

    返回:
        dict: 包含检查结果的字典，结构为:
            {
                "valid_dirs": list,   # 符合规范的目录列表
                "invalid_dirs": list, # 不符合规范的目录列表
                "error_details": {    # 错误详情
                    "missing_nfo": list,
                    "missing_images": list,
                    "missing_video": list
                }
            }

    异常:
        ValueError: 当输入路径不存在或不是目录时抛出
    """

    def _record_issues(subdir: Path, status: Dict, result: Dict, issues: List) -> None:
        """记录目录检查发现的问题"""
        logger.debug(f"开始记录目录问题: {subdir}")

        # 检查NFO文件
        if not status["has_nfo"]:
            logger.debug(f"目录缺少NFO文件: {subdir}")
            result["error_details"]["missing_nfo"].append(str(subdir))
            issues.append("缺少NFO文件")

        # 检查图片文件
        expected_images = {"poster", "fanart", "thumb"}
        if status["images"] != expected_images:
            missing = expected_images - status["images"]
            logger.debug(f"目录缺少图片文件: {subdir}, 缺少: {missing}")
            result["error_details"]["missing_images"].append({
                "path": str(subdir),
                "missing": list(missing)
            })
            issues.append(f"缺少图片文件: {missing}")

        # 检查视频文件
        if not status["has_video"]:
            logger.debug(f"目录缺少视频文件: {subdir}")
            result["error_details"]["missing_video"].append(str(subdir))
            issues.append("缺少视频文件")

        # 分类目录
        if issues:
            result["invalid_dirs"].append({
                "path": str(subdir),
                "issues": issues
            })
            logger.debug(f"添加到无效目录列表: {subdir}")
        else:
            result["valid_dirs"].append(str(subdir))
            logger.debug(f"添加到有效目录列表: {subdir}")

    def _generate_stats(result: Dict) -> None:
        """生成统计信息"""
        logger.debug("开始生成统计信息")
        result["stats"] = {
            "total": len(result["valid_dirs"]) + len(result["invalid_dirs"]),
            "valid_count": len(result["valid_dirs"]),
            "invalid_count": len(result["invalid_dirs"]),
            "error_distribution": {
                k: len(v) for k, v in result["error_details"].items()
            }
        }
        logger.info("统计信息: {}", result["stats"])

    logger.info(f"开始检查媒体目录: {dir_path}")

    result = {
        "valid_dirs": [],
        "invalid_dirs": [],
        "error_details": {
            "missing_nfo": [],
            "missing_images": [],
            "missing_video": []
        }
    }

    try:
        root_path = Path(dir_path)

        # 参数验证
        if not root_path.exists():
            logger.error(f"目录不存在: {dir_path}")
            raise ValueError(f"路径不存在: {dir_path}")
        if not root_path.isdir():
            logger.error(f"路径不是目录: {dir_path}")
            raise ValueError(f"路径不是目录: {dir_path}")

        logger.debug(f"开始遍历目录: {dir_path}")

        # 遍历所有子目录
        for subdir in root_path.listdir():
            if not subdir.isdir():
                logger.debug(f"跳过非目录项: {subdir}")
                continue

            logger.debug(f"检查子目录: {subdir}")
            check_status = {
                "has_nfo": False,
                "has_video": False,
                "images": set()
            }
            issues = []

            # 检查文件
            for file in subdir.walk(filter=FILES):
                if not file.isfile():
                    continue

                ext = file.ext.lower()
                stem = file.stem.lower()

                # 检查NFO文件
                if ext == ".nfo":
                    logger.debug(f"找到NFO文件: {file}")
                    check_status["has_nfo"] = True

                # 检查图片文件
                elif ext == ".jpg":
                    if "poster" in stem:
                        logger.debug(f"找到海报: {file}")
                        check_status["images"].add("poster")
                    elif "fanart" in stem:
                        logger.debug(f"找到同人画: {file}")
                        check_status["images"].add("fanart")
                    elif "thumb" in stem:
                        logger.debug(f"找到缩略图: {file}")
                        check_status["images"].add("thumb")

                # 检查视频文件
                elif ext in VIDEO_TYPE:
                    logger.debug(f"找到视频文件: {file}")
                    check_status["has_video"] = True

            # 记录问题
            _record_issues(subdir, check_status, result, issues)

            # 记录检查结果
            if issues:
                logger.error(f"目录检查不通过: {subdir} | 问题: {', '.join(issues)}")
            else:
                logger.success(f"目录检查通过: {subdir}")

        # 生成统计信息
        _generate_stats(result)
        logger.info("目录检查完成")
        logger.debug("检查结果: {}", result)

    except Exception as e:
        logger.exception(f"检查过程发生错误: {str(e)}")
        raise


@main.command()
@click.option("--source-path", required=True, help="云空间目录")
@click.option("--targer-path", required=True, help="本地目录")
def mirror_copy(source_path, targer_path) -> None:
    """将网盘的文件镜像到本地，对视频文件进行特殊处理。

    :param source_path: 网盘根目录路径
    :param targer_path: 本地根目录路径
    :raises OSError: 当文件操作失败时
    :raises Exception: 其他未预期的错误
    """
    # 转换为 Path 对象
    cloud_path = Path(source_path)
    local_path = Path(targer_path)

    # 验证源目录存在
    if not cloud_path.exists():
        logger.error(f"源目录不存在: {cloud_path}")
        return

    # 确保目标根目录存在
    local_path.mkdir(parents=True)

    try:
        # 遍历源目录下的所有文件
        for source_file in cloud_path.walk(filter=FILES):
            # 计算目标文件路径
            target_file = Path(source_file.replace(cloud_path, local_path))

            # 检查文件是否已存在
            if target_file.exists():
                logger.info(f"文件已存在，跳过: {target_file}")
                continue

            # 创建目标文件父目录
            target_file.parent.mkdir(parents=True)

            # 处理视频文件
            if source_file.ext.lower() in VIDEO_TYPE:
                logger.info(f"处理视频文件: {target_file}")
                try:
                    # 根据文件名选择源文件
                    source_template = (
                        Path("./scrapy_result/source_move_file-4K.mp4")
                        if "-4K" in target_file.stem.upper()
                        else Path("./scrapy_result/source_move_file.mp4")
                    )

                    # 检查模板文件是否存在
                    if not source_template.exists():
                        logger.error(f"模板文件不存在: {source_template}")
                        continue

                    # 复制文件
                    source_template.copy(target_file)
                    logger.success(f"视频文件复制完成: {target_file}")

                except Exception as e:
                    logger.error(f"视频文件处理失败: {target_file}")
                    logger.error(f"错误信息: {str(e)}")
                    # 清理失败的文件
                    if target_file.exists():
                        target_file.remove()
                    continue

    except Exception as e:
        logger.error(f"镜像复制过程发生错误: {str(e)}")
        raise


@main.command()
@click.option("--folder-path", required=True, help="目标文件")
def find_duplicate_files(folder_path: str):
    """
    查找重复的视频文件

    Args:
        folder_path: 要扫描的文件夹路径

    Returns:
        重复文件的完整路径列表
    """

    def _generate_delete_script(files: List[Path]):
        """
        生成删除脚本

        Args:
            files: 要删除的文件路径列表

        Returns:
            生成的脚本文件路径
        """
        if not files:
            logger.warning("没有文件需要删除")
            return

        try:
            # 创建脚本输出目录
            script_dir = Path(SCRIPT_DIR)
            script_dir.mkdir(parents=True)

            # 生成脚本文件名
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            script_path = Path(script_dir, f"delete_videos_{timestamp}.bat")

            # 生成删除脚本内容
            # 使用UTF-8编码
            script_content = [
                "@echo off",
                "chcp 65001",
                "echo 视频文件删除脚本",
                "echo 生成时间: %date% %time%",
                "echo.",
                "echo 将要删除以下文件:",
                "echo ----------------------"
            ]

            # 添加文件列表
            for i, inner_file_path in enumerate(files, 1):
                script_content.append(f"echo {i}. {inner_file_path}")

            script_content.extend([
                "echo ----------------------",
                "echo.",
                "set /p confirm=确认要删除这些文件吗？(Y/N): ",
                "if /i not \"%confirm%\"==\"Y\" (",
                "    echo 操作已取消",
                "    pause",
                "    exit /b",
                ")",
                "echo.",
                "echo 开始删除文件...",
                "echo."
            ])

            # 添加删除命令
            for inner_file_path in files:
                # 使用recycle命令移动到回收站（需要安装 cmdutils）
                script_content.append(f'del /f /q "{inner_file_path}"')
                # 添加删除确认检查
                script_content.extend([
                    f'if exist "{inner_file_path}" (',
                    f'    echo 删除失败: {inner_file_path}',
                    ') else (',
                    f'    echo 已删除: {inner_file_path}',
                    ')'
                ])

            # 添加脚本结束部分
            script_content.extend([
                "echo.",
                "echo 删除操作完成",
                "echo 请检查上述输出确认删除结果",
                "pause"
            ])

            # 写入脚本文件
            with open(script_path, 'w', encoding='utf-8') as inner_f:
                inner_f.write('\n'.join(script_content))

            # 生成文件列表
            list_file = Path(TEMP_DIR, f"delete_list_{timestamp}.txt")
            with open(list_file, 'w', encoding='utf-8') as inner_f:
                inner_f.write("要删除的文件列表:\n")
                inner_f.write("=" * 50 + "\n")
                for i, inner_file_path in enumerate(files, 1):
                    inner_f.write(f"{i}. {inner_file_path}\n")

            logger.success(f"删除脚本已生成: {script_path}")
            logger.success(f"文件列表已生成: {list_file}")

            return str(script_path)

        except Exception as inner_e:
            logger.exception(f"生成删除脚本失败: {inner_e}")
            raise

    record_file_path = RECORD_FILE
    try:
        logger.info(f"开始从文本中读取文件名:{record_file_path}")
        # 读取记录文件中的文件名
        with open(record_file_path, 'r', encoding='utf-8') as f:
            recorded_files = {line.strip() for line in f if line.strip()}
        logger.info(f"从记录文件中读取到 {len(recorded_files)} 个文件名")

        # 查找重复文件
        duplicate_files = []
        new_files = []
        folder = Path(folder_path)

        for file_path in folder.walk(filter=FILES):
            # 如果不是文件或者不是不是视频文件
            if file_path.ext.lower() not in VIDEO_TYPE:
                continue
            if file_path.stem in recorded_files:
                duplicate_files.append(file_path)
                logger.warning(f"发现重复文件: {file_path}")
            else:
                new_files.append(file_path)
                logger.info(f"发现新文件: {file_path}")

        logger.info("开始处理结果...")

        logger.info("追加新的记录...")
        # 追加新文件到记录
        if new_files:
            with open(record_file_path, 'a', encoding='utf-8') as f:
                for file_name in new_files:
                    f.write(f"{file_name.stem}\n")
            logger.success(f"已添加 {len(new_files)} 个新文件到记录")

        _generate_delete_script(duplicate_files)
        # 打印结果摘要
        print("\n检查结果摘要:")
        print(f"扫描文件总数: {len(recorded_files)}")
        print(f"新增文件数: {len(new_files)}")
        print(f"重复文件数: {len(duplicate_files)}")
    except Exception as e:
        logger.error(f"查找重复文件时出错: {e}")
        raise


@main.command()
@click.option("--folder-path", required=True, help="目标文件")
def create_virtual_files(folder_path: str):
    """
    为视频文件创建虚拟文件(.laoji)

    Args:
        folder_path: 要处理的根目录路径

    Returns:
        处理结果统计
    """
    result = {
        "processed": 0,
        "skipped": 0,
        "failed": 0,
        "details": []
    }

    try:
        root = Path(folder_path)
        if not root.exists():
            raise FileNotFoundError(f"目录不存在: {root}")

        logger.info(f"开始处理目录: {root}")

        # 使用unipath的walk方法遍历文件
        for file_path in root.walk(filter=FILES):
            if file_path.ext.lower() in VIDEO_TYPE:
                virtual_file = Path(file_path.parent, file_path.name + ".laoji")

                try:
                    if virtual_file.exists():
                        logger.debug(f"虚拟文件已存在，跳过: {virtual_file}")
                        result["skipped"] += 1
                        continue

                    # 创建空文件
                    with open(virtual_file, 'wb', buffering=0) as _:
                        pass
                    logger.info(f"创建虚拟文件: {virtual_file}")
                    result["processed"] += 1
                    result["details"].append({
                        "action": "created",
                        "path": str(virtual_file)
                    })

                except Exception as e:
                    logger.error(f"创建虚拟文件失败: {virtual_file} - {e}")
                    result["failed"] += 1
                    result["details"].append({
                        "action": "failed",
                        "path": str(virtual_file),
                        "error": str(e)
                    })

        logger.success(f"处理完成: 成功={result['processed']}, 跳过={result['skipped']}, 失败={result['failed']}")

        """打印处理结果"""
        if result:
            logger.success("\n=== 创建虚拟文件结果 ===")
            logger.success(f"成功: {result['processed']}")
            logger.success(f"跳过: {result['skipped']}")
            logger.success(f"失败: {result['failed']}")

            if result['failed'] > 0:
                logger.warning("\n失败详情:")
                for detail in result['details']:
                    if detail['action'] == 'failed':
                        logger.warning(f"- {detail['path']}: {detail['error']}")

    except Exception as e:
        logger.exception(f"处理过程发生错误: {e}")
        raise


@main.command()
@click.option("--log-path", required=True, help="日志文件路径")
def analyze_log(log_path: str):
    """
    分析日志文件并生成删除脚本

    Args:
        log_path: 日志文件路径
    """

    def _parse_log_file(log_file):
        """
        解析日志文件

        Args:
            log_file: 日志文件路径

        Returns:
            List[Dict]: 解析结果列表,每项包含temp_dir和file_path
        """
        results = []
        temp_dir = None

        try:
            with open(log_file, 'r', encoding='utf-8') as f:
                prev_line = ''
                for line in f:
                    line = line.strip()

                    # 检查是否包含目录删除信息
                    if 'Deleting directory' in line:
                        temp_dir = line.split('Deleting directory')[-1].strip()
                        logger.debug(f"找到目录: {temp_dir}")

                        # 检查上一行是否包含文件信息
                        if temp_dir and 'Removing item from database' in prev_line:
                            if 'Path:' in prev_line and ', Id:' in prev_line:
                                file_path = prev_line.split('Path:')[-1].split(', Id:')[0].strip()

                                # 验证文件路径是否在temp_dir下
                                if str(temp_dir) in str(Path(file_path).parent):
                                    logger.info(f"找到匹配文件: {file_path}")
                                    results.append({
                                        'temp_dir': temp_dir,
                                        'file_path': file_path
                                    })

                    prev_line = line

            return results

        except Exception as e:
            logger.error(f"解析日志文件失败: {str(e)}")
            raise

    def _generate_delete_script(files):
        """
        生成删除脚本

        Args:
            files: 要删除的文件信息列表

        Returns:
            str: 生成的脚本文件路径
        """
        if not files:
            logger.warning("没有找到需要删除的文件")
            return

        try:
            # 创建脚本目录
            script_dir = Path(SCRIPT_DIR)
            script_dir.mkdir(parents=True)

            # 生成脚本文件名
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            script_path = Path(script_dir, f"analyze_log_{timestamp}.bat")

            # 生成脚本内容
            script_content = [
                "@echo off",
                "chcp 65001",
                "echo 文件删除脚本",
                "echo 生成时间: %date% %time%",
                "echo.",
                "echo 将要删除以下文件:",
                "echo ----------------------"
            ]

            # 添加文件列表
            for i, file_info in enumerate(files, 1):
                script_content.append(f"echo {i}. {file_info['file_path']}")

            script_content.extend([
                "echo ----------------------",
                "echo.",
                "set /p confirm=确认要删除这些文件吗？(Y/N): ",
                "if /i not \"%confirm%\"==\"Y\" (",
                "    echo 操作已取消",
                "    pause",
                "    exit /b",
                ")",
                "echo.",
                "echo 开始删除文件...",
                "echo."
            ])

            # 添加删除命令
            for file_info in files:
                file_path = Path(file_info['file_path'])
                file_path = Path(r'Y:\艺术视频', file_path.parent.parent.name, file_path.name)
                script_content.append(f'if exist "{file_path}" (')
                script_content.append(f'    del /f /q "{file_path}"')
                script_content.append(f'    if exist "{file_path}" (')
                script_content.append(f'        echo 删除失败: {file_path}')
                script_content.append('    ) else (')
                script_content.append(f'        echo 已删除: {file_path}')
                script_content.append('    )')
                script_content.append(')')

            # 添加脚本结束部分
            script_content.extend([
                "echo.",
                "echo 删除操作完成",
                "echo 请检查上述输出确认删除结果",
                "pause"
            ])

            # 写入脚本文件
            with open(script_path, 'w', encoding='utf-8') as f:
                f.write('\n'.join(script_content))

            logger.success(f"删除脚本已生成: {script_path}")
            return str(script_path)

        except Exception as e:
            logger.exception(f"生成删除脚本失败: {e}")
            raise

    def _generate_delete_dir_script(files):
        """
        生成删除目录脚本

        Args:
            files: 要删除的文件信息列表

        Returns:
            str: 生成的脚本文件路径
        """
        if not files:
            logger.warning("没有找到需要删除的文件")

        # 生成文件列表
        list_file = Path(Path(TEMP_DIR), f"analyze_log_dir_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt")
        list_file.parent.mkdir(parents=True)

        with open(list_file, 'w', encoding='utf-8') as f:
            f.write("要删除的文件列表:\n")
            f.write("=" * 50 + "\n")
            for i, file_info in enumerate(results, 1):
                file_path = Path(file_info['file_path']).parent
                file_path = Path(r'Y:\影视剧集', file_path.parent.name, file_path.name)
                f.write(f"rd /s /q \"{file_path}\"\n")

    try:
        log_file = Path(log_path)
        if not log_file.exists():
            raise FileNotFoundError(f"日志文件不存在: {log_file}")

        if log_file.ext.lower() != '.txt':
            raise ValueError(f"不支持的文件类型: {log_file.ext}")

        logger.info(f"开始分析日志文件: {log_file}")

        # 解析日志文件
        results = _parse_log_file(log_file)

        if results:
            logger.info(f"找到 {len(results)} 个需要删除的文件")

            av_results = []
            movie_result = []
            for item_result in results:
                if '艺术视频' in str(item_result):
                    av_results.append(item_result)
                else:
                    movie_result.append(item_result)
            # 生成删除脚本
            _generate_delete_script(av_results)
            _generate_delete_dir_script(movie_result)

            # 生成文件列表
            list_file = Path(Path(TEMP_DIR), f"analyze_log_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt")
            list_file.parent.mkdir(parents=True)

            with open(list_file, 'w', encoding='utf-8') as f:
                f.write("要删除的文件列表:\n")
                f.write("=" * 50 + "\n")
                for i, file_info in enumerate(results, 1):
                    f.write(f"{file_info['file_path']}\n")

            logger.success(f"文件列表已生成: {list_file}")
        else:
            logger.warning("未找到需要删除的文件")

    except Exception as e:
        logger.exception(f"分析日志文件时出错: {e}")
        raise


@main.command()
@click.option('--source', required=True, help="源目录")
@click.option('--prefix', default="SONE", help="文件前缀（默认：SONE）")
def find_missing(source: str, prefix: str):
    """查找缺失的编号"""
    missing = find_missing_numbers(source, prefix)

    if missing:
        logger.info("缺失的编号列表：")
        for num in missing:
            logger.info(f"Missing: {prefix}-{num}")
    else:
        logger.info("没有找到缺失编号")


def _format_json(data: Union[str, dict, list], indent: int = 2) -> str:
    """
    格式化 JSON 数据为易读的字符串形式

    Args:
        data: 要格式化的数据，可以是 JSON 字符串、字典或列表
        indent: 缩进空格数，默认为 2

    Returns:
        str: 格式化后的 JSON 字符串

    Raises:
        json.JSONDecodeError: 当输入的 JSON 字符串格式无效时
        TypeError: 当输入的数据类型不支持时
    """
    try:
        # 如果输入是字符串，先解析成 Python 对象
        if isinstance(data, str):
            parsed_data = json.loads(data)
        else:
            parsed_data = data

        # 格式化输出
        formatted_json = json.dumps(
            parsed_data,
            indent=indent,
            ensure_ascii=False,  # 确保中文正确显示
            sort_keys=True  # 按键排序，使输出更稳定
        )
        return formatted_json

    except json.JSONDecodeError as e:
        raise json.JSONDecodeError(f"无效的 JSON 字符串: {str(e)}", e.doc, e.pos)
    except TypeError as e:
        raise TypeError(f"不支持的数据类型: {type(data)}")


def _print_json(data: Union[str, dict, list], indent: int = 2) -> None:
    """
    直接打印格式化的 JSON 数据

    Args:
        data: 要打印的数据，可以是 JSON 字符串、字典或列表
        indent: 缩进空格数，默认为 2
    """
    try:
        formatted = _format_json(data, indent)
        print(formatted)
    except (json.JSONDecodeError, TypeError) as e:
        print(f"错误: {str(e)}")


def find_missing_numbers(source_dir: str, prefix: str = "SONE"):
    """
    查找缺失的编号
    :param source_dir: 源目录路径
    :param prefix: 文件名前缀（默认SONE）
    :return: 排序后的缺失编号列表
    """
    pattern = re.compile(rf"^{prefix}-(\d+)(?:-|$)", re.IGNORECASE)
    numbers = []
    source_dir = Path(source_dir)

    # 处理文件名
    for file_path in source_dir.walk(filter=FILES):
        # 仅处理文件名（不含扩展名）
        stem = file_path.stem
        match = pattern.match(stem)

        if not match:
            logger.warning(f"文件名格式不匹配: {file_path}")
            continue

        try:
            num = int(match.group(1))
            numbers.append(num)
        except ValueError:
            logger.error(f"编号解析失败: {file_path}")
            continue

    # 没有文件
    if not numbers:
        return []

    # 排序并去重
    sorted_numbers = sorted(set(numbers))
    missing = []

    # 查找缺失编号
    for i in range(1, len(sorted_numbers)):
        prev = sorted_numbers[i - 1]
        curr = sorted_numbers[i]

        if curr - prev > 1:
            missing.extend(range(prev + 1, curr))

    logger.info(f"找到 {len(missing)} 个缺失编号")
    return missing


if __name__ == '__main__':
    """
    
    查看指定文件夹的数据是否重复
    python jav_process_ai.py find-duplicate-files --folder-path "Y:\数据工厂\脏数据"
    
    镜像数据
    python jav_process_ai.py mirror-copy --source-path "Y:\数据工厂\脏数据" --targer-path "E:\临时文件\数据工厂\原始数据"
    
    检查已经刮削的视频是否标准
    python jav_process_ai.py check-movie-info --dir-path "E:\临时文件\数据工厂\处理完成"
    python jav_process_ai.py check-movie-info --dir-path "E:\临时文件\meta-data"
     
    # 创建虚拟文件
    python jav_process_ai.py create-virtual-files --folder-path "E:\临时文件\数据工厂\处理完成"
    python jav_process_ai.py create-virtual-files --folder-path "E:\临时文件\数据工厂\success"
    
    # 分析已经删除的文件
    python jav_process_ai.py analyze-log --log-path "D:\Program Files\programdata\logs\embyserver.txt"
    
    # 查找其他前缀的缺失编号
    python jav_process_ai.py find-missing --source "Y:\\艺术视频\\SONE" --prefix SONE
    

    """
    main()
